package com.innovation.chengzhangriji.service;

import android.content.Intent;
import android.os.IBinder;

import com.google.gson.JsonElement;
import com.innovation.chengzhangriji.BabyAndParent;
import com.innovation.chengzhangriji.Config;
import com.innovation.chengzhangriji.R;
import com.innovation.chengzhangriji.database.DatabaseManager;
import com.innovation.chengzhangriji.http.AllBabyResponse;
import com.innovation.chengzhangriji.http.Auth;
import com.innovation.chengzhangriji.http.BabyResponse;
import com.innovation.chengzhangriji.http.Client;
import com.innovation.chengzhangriji.http.DataResponse;
import com.innovation.chengzhangriji.http.ResponseHandler;
import com.innovation.chengzhangriji.preferences.LoginInfo;
import com.innovation.chengzhangriji.ui.event.BaseEvent;
import com.innovation.chengzhangriji.ui.event.BaseTimelineEvent;
import com.orhanobut.logger.Logger;

import de.greenrobot.event.EventBus;

public class SyncTimelineService extends BaseSyncTimelineService {

    @Override
    protected void onTimelineStartCommand() {
        LoginInfo login = Config.getLoginInfo(this);
        if (login == null) {
            stopSelf();
            return;
        }
        checkPermission(login);
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void checkPermission(final LoginInfo login) {
        final String phone = login.getPhone();
        final String token = login.getToken().getAccessToken();
        final String userId = login.getUserID();
        final int babyId = login.getBabyID();
        if (babyId == LoginInfo.EMPTY_BABY_ID) {
            sendDelete();
            stopSelf();
            return;
        }
        Client.requestAllBaby(this, phone, token, new ResponseHandler() {

            @Override
            public void onInnovationSuccess(JsonElement value) {
                BabyAndParent babyAndParent = DatabaseManager.getInstance(SyncTimelineService.this).queryBabyAndParent(userId, babyId);
                if (babyAndParent == null) {
                    sendDelete();
                    stopSelf();
                    return;
                }
                int babyId = babyAndParent.getBabyID();
                int range = babyAndParent.getRange();
                int permission = babyAndParent.getPermission();
                boolean deleted = true;
                AllBabyResponse response = get(value.toString(), AllBabyResponse.class);
                if (response != null) {
                    int length = response.getData().length;
                    int[] childIDArray = new int[length];
                    Auth[] auth = new Auth[length];
                    for (int i = 0; i < length; i++) {
                        childIDArray[i] = response.getData()[i].getId();
                        auth[i] = response.getData()[i].getAuth();
                        if (babyId == response.getData()[i].getId()){
                            deleted = false;
                            if(range != response.getData()[i].getAuth().getRange()) {
                                deleteTimeline(babyId);
                                deleteSyncTs(babyId);
                                deleteLastSyncTs(babyId);
                                sendDeleteTimeline();
                            }
                            if (permission != response.getData()[i].getAuth().getPermission()) {
                                sendChangePermission();
                            }
                        }
                    }
                    if(deleted) {
                        sendDelete();
                    } else {
                        insertOrReplaceInTxBabyAndParent(userId, auth, childIDArray);
                        insertOrReplaceInTxBaby(response.getData());
                        syncData(login, babyId, querySyncTS(babyId));
                    }
                } else {
                    sendDelete();
                    stopSelf();
                }
            }

            @Override
            public void onChZhRJFailure(String value) {
                super.onChZhRJFailure(value);
                syncFailure(value);
            }

            @Override
            public void onChZhRJTokenFailure(String value) {
                super.onChZhRJTokenFailure(value);
                syncTokenFailure(value);
                stopSelf();
            }

        }, new Client.NetworkUnavailableListener() {
            @Override
            public void networkUnavailable() {
                syncFailure(getString(R.string.tip_network_unavailable));
            }
        });
    }

    private void syncData(final LoginInfo login, final int babyId, final long syncTS) {
        final String phone = login.getPhone();
        final String token = login.getToken().getAccessToken();
        Client.requestSyncData(this, phone, token, babyId, Config.QUERY_LENGTH, syncTS, new ResponseHandler() {

            @Override
            public void onInnovationStart() {
                syncStart();
            }

            @Override
            public void onInnovationSuccess(JsonElement value) {
                super.onInnovationSuccess(value);
                DataResponse dataResponse = get(value.toString(), DataResponse.class);
                if (dataResponse == null) {
                    syncSuccess(0, 0);
                    stopSelf();
                    return;
                }

                long newSyncTS = dataResponse.getSyncTS();
                long createTS = dataResponse.getCreateTS();
                int remainNumber = dataResponse.getRemainNumber();
                int length = dataResponse.getData().length;

                if (newSyncTS != syncTS) {
                    insertOrReplaceSeverTime(babyId, newSyncTS);
                }

                if (length > 0) {
                    insertOrReplaceInTxTimeline(babyId, dataResponse);
                    if (remainNumber > 0) {
                        String uuid = null;
                        for (int i = 0; i < length; i++) {
                            if (dataResponse.getData()[i].getState() == 1) {
                                uuid = dataResponse.getData()[i].getUuid();
                            }
                        }
                        insertOrReplaceLastServerTime(babyId, uuid, newSyncTS, createTS, remainNumber);
                        syncSuccess(length, remainNumber);
                        stopSelf();
                    } else {
                        syncSuccess(length, 0);
                        stopSelf();
                    }
                } else {
                    syncSuccess(0, 0);
                    stopSelf();
                }
            }

            @Override
            public void onChZhRJFailure(String value) {
                syncFailure(value);
                stopSelf();
            }

            @Override
            public void onChZhRJTokenFailure(String value) {
                syncTokenFailure(value);
                stopSelf();
            }

        }, new Client.NetworkUnavailableListener() {
            @Override
            public void networkUnavailable() {
                syncFailure(getString(R.string.tip_network_unavailable));
            }
        });
    }

    private void sendDelete() {
//        Intent intent = new Intent();
//        intent.setAction("delete");
//        sendBroadcast(intent);

        BaseEvent event = new BaseEvent(BaseEvent.TYPE_BABY_DELETED);
        EventBus.getDefault().post(event);
    }

    private void syncStart() {
//        Intent intent = new Intent();
//        intent.setAction(Config.ACTION_SYNC_TIMELINE_START);
//        sendBroadcast(intent);
    }

    private void syncSuccess(int updateNumber, int remainNumber) {
//        Intent intent = new Intent();
//        intent.setAction(Config.ACTION_SYNC_TIMELINE_SUCCESS);
//        intent.putExtra(Config.ACTION_EXTERNAL_UPDATE_NUMBER, updateNumber);
//        intent.putExtra(Config.ACTION_EXTERNAL_REMAIN_NUMBER, remainNumber);
//        sendBroadcast(intent);

        BaseTimelineEvent event = new BaseTimelineEvent(remainNumber, 0, updateNumber);
        event.setType(BaseEvent.TYPE_TIMELINE_SYNC);
        event.setState(BaseEvent.STATE_SUCCESS);
        EventBus.getDefault().post(event);
    }

    public void sendDeleteTimeline() {

        BaseEvent event = new BaseEvent(BaseEvent.TYPE_RANGE_CHANGED);
        EventBus.getDefault().post(event);
    }

    public void sendChangePermission() {

        BaseEvent event = new BaseEvent(BaseEvent.TYPE_PERMISSION_CHANGED);
        EventBus.getDefault().post(event);
    }

    private void syncFailure(String value) {
//        Intent intent = new Intent();
//        intent.setAction(Config.ACTION_SYNC_TIMELINE_FAILURE);
//        intent.putExtra(Config.ACTION_EXTERNAL_MESSAGE, value);
//        sendBroadcast(intent);

        BaseTimelineEvent event = new BaseTimelineEvent(0, 0, 0);
        event.setType(BaseEvent.TYPE_TIMELINE_SYNC);
        event.setState(BaseEvent.STATE_FAILURE);
        event.setMessage(value);
        EventBus.getDefault().post(event);
        stopSelf();
    }

    private void syncTokenFailure(String value) {
//        Intent intent = new Intent();
//        intent.setAction(Config.ACTION_SYNC_TIMELINE_TOKEN_FAILURE);
//        intent.putExtra(Config.ACTION_EXTERNAL_MESSAGE, value);
//        sendBroadcast(intent);

        BaseTimelineEvent event = new BaseTimelineEvent(0, 0, 0);
        event.setMessage(value);
        event.setType(BaseEvent.TYPE_TIMELINE_SYNC);
        event.setState(BaseEvent.STATE_TOKEN_ERROR);
        EventBus.getDefault().post(event);
    }

    protected final void insertOrReplaceInTxBabyAndParent(String id, Auth[] auth, int... babyIDArray) {
        DatabaseManager.getInstance(this).insertOrReplaceInTxBabyAndParent(id, auth, babyIDArray);
    }

    protected final void insertOrReplaceInTxBaby(BabyResponse... babyResponses) {
        DatabaseManager.getInstance(this).insertOrReplaceInTxBaby(babyResponses);
    }

    protected final void deleteTimeline(int babyId) {
        DatabaseManager.getInstance(this).deleteTimeline(babyId);
    }

    protected final void deleteSyncTs(int babyId) {
        DatabaseManager.getInstance(this).deleteSyncTs(babyId);
    }

    protected final void deleteLastSyncTs(int babyId) {
        DatabaseManager.getInstance(this).deleteLastSyncTs(babyId);
    }
}
